//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// (C) Copyright 2006 Marvell International Ltd.
// All Rights Reserved
//
//------------------------------------------------------------------------------
//
//  File: intr.c
//
//  This file implement major part of interrupt module for the Marvell PXA Processor SoC.
//
#include <windows.h>
#include <ceddk.h>
#include <nkintr.h>
#include <monahans.h>
#include "oal_log.h"
#include "oal_memory.h"
#include "oal_io.h"
#include "oal_timer.h"
#include "oal_intr.h"
#include <intr.h>
#include "xllp_lcd.h"

// IPM
#include "ipm_xllp_pm_dvfm.h"
UINT32 gIPM_LCDEOF_FCS;
XLLP_PM_FV_INFO gIPM_Current_OP, gIPM_Next_OP;



//------------------------------------------------------------------------------
// Defines 
#define NUM_INT_PRIOS    (XLLP_INTC_S_MAX_ID+1)
#define NUM_GPIO		 (XLLP_GPIO_ID_MAX+1)

// External Functions

// External Variables 
extern UINT32   g_GPIOEdgeDetect[NUM_GPIO];
extern  int stop_idle_profiler;
// Types
 
// Global Variables 
PFN_PROFILER_ISR g_pProfilerISR = NULL;

static XLLP_INTC_T *g_pICReg = NULL;
static XLLP_GPIO_T *g_pGPIO = NULL;

// extern BSP_ARGS *g_pBSPArgs;
	
static UINT32   g_IntPriorities[NUM_INT_PRIOS] =
{
    IRQ_OSMRXX_4,      // M4-M11 M4-Scheduler- ID 7
    IRQ_PMU,           // PMU - ID 12
    IRQ_GPIO1,         // GPIO1 edge detect - Suspend/Resume - ID 9
    IRQ_RTCALARM,      // RTC Alarm - ID 31
    IRQ_BASEBAND,      // Baseband - ID 1
    IRQ_DMAC,          // DMA Controller - ID 25
    XLLP_INTC_S_MSL1,     
    XLLP_INTC_S_KEY,     
    IRQ_USBFN,         // UDC - ID 11
    IRQ_USBOHCI,       // USB Host (OHCI) - ID 3
    IRQ_USBNONOHCI,    // USB Host Non-OHCI - ID 2
    IRQ_FFUART,        // FFUART - ID 22
    IRQ_STUART,        // STDUART - ID 20
    IRQ_BTUART,        // BTUART - ID 21
	IRQ_GPIOXX_2, 	   // GPIOxx_2 - ID 10	
    IRQ_AC97,          // AC97 - UCB1400 - ID 14
    IRQ_GPIO0,         // GPIO0 - FPGA - ID 8
    IRQ_MMC,           // MMC - ID 23
    IRQ_MEMSTICK,      // Memstick - ID 5
    IRQ_USIM,          // USIM (Smart Card) - ID 15
    IRQ_OSMR0,         // M0 - ID 26    
    IRQ_OSMR1,         // M1 - ID 27
    IRQ_OSMR2,         // M2 - ID 28
    IRQ_OSMR3,         // M3 - ID 29
    XLLP_INTC_S_SSP3, 
    XLLP_INTC_S_SSP2, 
    XLLP_INTC_S_SSP4,
    XLLP_INTC_S_SSP1, 
    XLLP_INTC_S_PI2C, 
    XLLP_INTC_S_I2C,
    IRQ_LCD,            // LCDC - ID 17
    XLLP_INTC_S_RTC_ONE, 
    XLLP_INTC_S_TPM,      
    XLLP_INTC_S_CAMERA,   
    XLLP_INTC_S_CIR,      
    0x0,				//reserved     
    XLLP_INTC_S_TSI,      
    0x0,
    XLLP_INTC_S_USIM2,    
    XLLP_INTC_S_GRAPHICS, 
    0x0,
    XLLP_INTC_S_MMC2,     
    0x0,			// Reserved for bit 42
    0x0,   		// Reserved for bit 43
    XLLP_INTC_S_1WIRE,    
    XLLP_INTC_S_NAND,     
    XLLP_INTC_S_USB2,     
    XLLP_INTC_S_SGP,      
    XLLP_INTC_S_MVED_DMA,
    XLLP_INTC_S_EXT1,     
    XLLP_INTC_S_EXT2,     
    XLLP_INTC_S_DMEM,     
    XLLP_INTC_S_CLK,      
    0x0, //53
    XLLP_INTC_S_MVED1,
    XLLP_INITC_S_MMC3,  //55
};

// Local Variables 

// Local Functions 


//------------------------------------------------------------------------------
//
//  Function:  OALIntrInit
//
//  This function initialize interrupt mapping, hardware and call platform
//  specific initialization.
//

BOOL OALIntrInit()
{
    BOOL rc = FALSE;
    UINT8 nIntPrio;
    UINT32 i;
#ifdef ENABLE_RCOMP
    XLLP_MEMC_T memc;
#endif

    OALMSG( OAL_FUNC&&OAL_INTR, (L"+OALInterruptInit\r\n") );
	OALMSG(1, (L"+OALIntrInit\r\n"));

    // Initialize interrupt mapping
    OALIntrMapInit();

    // Map a pointer to the interrupt/gpio controller.
    //
    g_pICReg = (XLLP_INTC_T *) OALPAtoVA(MONAHANS_BASE_REG_PA_INTC, FALSE);
    g_pGPIO = (XLLP_GPIO_T *) OALPAtoVA(MONAHANS_BASE_REG_PA_GPIO, FALSE);

    // Configure interrupt priorities.
    //
    for (nIntPrio = 0 ; nIntPrio < NUM_INT_PRIOS ; nIntPrio++)
    {
        if (nIntPrio<32)
            g_pICReg->ipr[nIntPrio%32] = ((1 << 31) | g_IntPriorities[nIntPrio]);
    	else
        	g_pICReg->ipr2[nIntPrio-32] = ((1 << 31) | g_IntPriorities[nIntPrio]);
    }

    //
    // Set DIM, the only bit in the ICCR.  
    // The effect is that only enabled and unmasked
    // interrupts bring the processor out of IDLE mode.
    //
    g_pICReg->iccr = 0x1;

#ifdef OAL_BSP_CALLBACKS
    // Give BSP change to initialize subordinate controller
    rc = BSPIntrInit();
#else
    rc = TRUE;
#endif

    // Setup static interrupt mappings (first one isn't really needed)
#ifdef PMU_TICKS_ENABLED
    OALIntrStaticTranslate(SYSINTR_RESCHED, IRQ_PMU);
#else
    //this is not actually required, since OSMR4 match is directly processed inside the OEMInterruptHandler()
    //OALIntrStaticTranslate(SYSINTR_RESCHED, IRQ_OSMR4);
#endif
    OALIntrStaticTranslate(SYSINTR_RTC_ALARM, IRQ_RTCALARM);

    // Mask all GPIO edge detect.
    
    for( i=0;i<NUM_GPIO; i++ )
    {
    	XllpGpioSetRisingEdgeDetectEnable((P_XLLP_GPIO_T)g_pGPIO, i, XLLP_OFF);	
	   	XllpGpioSetFallingEdgeDetectEnable((P_XLLP_GPIO_T)g_pGPIO,i, XLLP_OFF);
    }
    // Enable the interrupt root for GPIO 2 - xx.
    // Since all edge detects are disabled, this will not lead to any interrupt.
   	XllpINTCEnableSource(XLLP_INTC_S_GPIOX,XLLP_TRUE);

#ifdef ENABLE_RCOMP
    // initiate the RCOMP eval, and enable RCOMP interrupt.
    memc.dmem=( XLLP_UINT32_T) OALPAtoVA(MONAHANS_BASE_REG_PA_DMEMC, FALSE);
    memc.rcEvalInterval=0x13D62; //0.2 second RCOMP updates
    memc.rcRange=2;          // resistive compensation range
    OALMSG(OAL_INTR, (L"OALIntrInit: to start the RCOMP eval, and enable RCOMP interrupts\r\n"));
    XllpMemcRcompInit(&memc);
    XllpINTCEnableSource(XLLP_INTC_S_DMEM, XLLP_TRUE);//enable DMEM interrupt
#endif
    OALMSG(OAL_INTR&&OAL_FUNC, (L"-OALInterruptInit(rc = %d)\r\n", rc));
	OALMSG(1, (L"-OALIntrInit\r\n"));

    gIPM_LCDEOF_FCS  = 0;


    return rc;
}


//------------------------------------------------------------------------------
//
//  Function:  OALIntrRequestIrqs
//
//  This function returns IRQ for CPU/SoC devices based on their
//  physical address.
//
BOOL OALIntrRequestIrqs(DEVICE_LOCATION *pDevLoc, UINT32 *pCount, UINT32 *pIrqs)
{
    BOOL rc = FALSE;

    OALMSG(OAL_INTR&&OAL_FUNC, (
        L"+OALIntrRequestIrqs(0x%08x->%d/%d/0x%08x/%d, 0x%08x, 0x%08x)\r\n",
        pDevLoc, pDevLoc->IfcType, pDevLoc->BusNumber, pDevLoc->LogicalLoc,
        pDevLoc->Pin, pCount, pIrqs
    ));

    // This shouldn't happen
    if (*pCount < 1) goto cleanUp;

#ifdef OAL_BSP_CALLBACKS
    rc = BSPIntrRequestIrqs(pDevLoc, pCount, pIrqs);
#endif    

cleanUp:        
    OALMSG(OAL_INTR&&OAL_FUNC, (L"-OALIntrRequestIrqs(rc = %d)\r\n", rc));

    return rc;
}


//------------------------------------------------------------------------------
//
//  Function:  OALIntrEnableIrqs
//
BOOL OALIntrEnableIrqs(UINT32 count, const UINT32 *pIrqs)
{
    BOOL rc = TRUE;
    UINT32 irq, i;

    OALMSG(OAL_INTR&&OAL_FUNC, (
        L"+OALIntrEnableIrqs(%d, 0x%08x)\r\n", count, pIrqs
    ));
    
    for (i = 0; i < count; i++) {
#ifndef OAL_BSP_CALLBACKS
        irq = pIrqs[i];
#else
        // Give BSP chance to enable irq on subordinate interrupt controller
        irq = BSPIntrEnableIrq(pIrqs[i]);
        if (irq == OAL_INTR_IRQ_UNDEFINED) continue;
#endif
        if (irq <= XLLP_INTC_S_MAX_ID) {
            // Enable the primary IRQ
        (void) XllpINTCEnableSource(irq,XLLP_TRUE);
        } else if (g_pGPIO && (irq<=IRQ_GPIO_SHARE_MAX)) {

			OALMSG(OAL_INTR&&OAL_FUNC, (  L"+OALIntrEnableIrqs(%d)\r\n", irq  ));

       	    if (GPIO_RISE&g_GPIOEdgeDetect[IRQ_TO_GPIO_NUM(irq)])
       	    	XllpGpioSetRisingEdgeDetectEnable(g_pGPIO, IRQ_TO_GPIO_NUM(irq), XLLP_ON);
       	    if (GPIO_FALL&g_GPIOEdgeDetect[IRQ_TO_GPIO_NUM(irq)])
       	    	XllpGpioSetFallingEdgeDetectEnable(g_pGPIO, IRQ_TO_GPIO_NUM(irq), XLLP_ON);
        } else {
            rc = FALSE;
        }            
    }

    OALMSG(OAL_INTR&&OAL_FUNC, (L"-OALIntrEnableIrqs(rc = %d)\r\n", rc));
    return rc;    
}


//------------------------------------------------------------------------------
//
//  Function:  OALIntrDisableIrqs
//
VOID OALIntrDisableIrqs(UINT32 count, const UINT32 *pIrqs)
{
    UINT32 irq, i;

    OALMSG(OAL_INTR&&OAL_FUNC, (
        L"+OALIntrDisableIrqs(%d, 0x%08x)\r\n", count, pIrqs
    ));
    
    for (i = 0; i < count; i++) {
#ifndef OAL_BSP_CALLBACKS
        irq = pIrqs[i];
#else
        // Give BSP chance to disable irq on subordinate interrupt controller
        irq = BSPIntrDisableIrq(pIrqs[i]);
#endif
        if (irq <= XLLP_INTC_S_MAX_ID) {
            // Disable the primary IRQ
        (void) XllpINTCEnableSource(irq,XLLP_FALSE);
        } else if (g_pGPIO && (irq<=IRQ_GPIO_SHARE_MAX)) {
			OALMSG(OAL_INTR&&OAL_FUNC, (  L"+OALIntrEnableIrqs(%d)\r\n", irq  ));
       	    if (GPIO_RISE&g_GPIOEdgeDetect[IRQ_TO_GPIO_NUM(irq)])
       	    	XllpGpioSetRisingEdgeDetectEnable(g_pGPIO, IRQ_TO_GPIO_NUM(irq), XLLP_OFF);
       	    if (GPIO_FALL&g_GPIOEdgeDetect[IRQ_TO_GPIO_NUM(irq)])
       	    	XllpGpioSetFallingEdgeDetectEnable(g_pGPIO, IRQ_TO_GPIO_NUM(irq), XLLP_OFF);
        }            
    }

    OALMSG(OAL_INTR&&OAL_FUNC, (L"-OALIntrDisableIrqs\r\n"));
}


//------------------------------------------------------------------------------
//
//  Function:  OALIntrDoneIrqs
//
VOID OALIntrDoneIrqs(UINT32 count, const UINT32 *pIrqs)
{
    UINT32 irq, i;

    OALMSG(OAL_INTR&&OAL_VERBOSE, (
        L"+OALIntrDoneIrqs(%d, 0x%08x)\r\n", count, pIrqs
    ));

    for (i = 0; i < count; i++) {
#ifndef OAL_BSP_CALLBACKS
        irq = pIrqs[i];
#else
        // Give BSP chance to finish irq on subordinate interrupt controller
        irq = BSPIntrDoneIrq(pIrqs[i]);
        if (irq == OAL_INTR_IRQ_UNDEFINED) continue;
#endif
        if (irq <= XLLP_INTC_S_MAX_ID) {
            // Enable the primary IRQ
        (void) XllpINTCEnableSource(irq,XLLP_TRUE);
        } else if (g_pGPIO && (irq<=IRQ_GPIO_SHARE_MAX)) {
			OALMSG(OAL_INTR&&OAL_FUNC, (  L"+OALIntrEnableIrqs(%d)\r\n", irq  ));
   	    	// We are not disabling edge detect any more in process of GPIO int.
   	    	// in order to prevent int loss.
   	    	// So nothing to resume here.
   	    	//XllpGpioClearEdgeDetectStatus(g_pGPIO, IRQ_TO_GPIO_NUM(irq));
       	    //if (GPIO_RISE&g_GPIOEdgeDetect[IRQ_TO_GPIO_NUM(irq)])
       	    //	XllpGpioSetRisingEdgeDetectEnable(g_pGPIO, IRQ_TO_GPIO_NUM(irq), XLLP_ON);
       	    //if (GPIO_FALL&g_GPIOEdgeDetect[IRQ_TO_GPIO_NUM(irq)]) 
       	    //	XllpGpioSetFallingEdgeDetectEnable(g_pGPIO, IRQ_TO_GPIO_NUM(irq), XLLP_ON);
        }            
    }

    OALMSG(OAL_INTR&&OAL_VERBOSE, (L"-OALIntrDoneIrqs\r\n"));
}


//------------------------------------------------------------------------------
//
//  Function:  OEMInterruptHandler
//

//#ifdef IPM_IPROF
extern BOOL IPM_WindowDone(UINT32 *nextWindowIncrement);
DWORD iprof_sysintr = SYSINTR_NOP;
void IPM_DoFCS(XLLP_PM_FV_INFO *nextOP, BOOL HSIOOnly, BOOL changeHSIO);

extern XLLP_LCD_T xllp_lcd;

ULONG OEMInterruptHandler(ULONG ra)
{
    UINT32 irq = OAL_INTR_IRQ_UNDEFINED;
    UINT32 sysIntr = SYSINTR_NOP;


    if (!g_pICReg) {
        return(SYSINTR_NOP);
    }

    // Determine the IRQ of the highest priority pending interrupt
// Bvd way    irq = (UINT16)((g_pICReg->ichp >> 16) & 0x3F);

   // Two steps for now, maybe condense later.
    irq = XllpReadINTCReg(XLLP_INTC_ICHP);

    irq = (irq >> 16) & 0x3F;

    if (irq == 0)
    {
        return(SYSINTR_NOP);
    }



    // System timer interrupt?
    else if(irq == IRQ_OSMRXX_4)
    {
        P_XLLP_OST_T pOSTRegs = (P_XLLP_OST_T)OALPAtoVA(MONAHANS_BASE_REG_PA_OST, FALSE);

        if (pOSTRegs->ossr & XLLP_OSSR_M4)
        {
            //OALMSG(1, (L"ISR:OSCR4!\r\n"));

                sysIntr = OALTimerIntrHandler();

        }
    }
    else if (irq == IRQ_OSMR0)
    {
        // The rest is up to the timer interrupt handler.
        // Never update it using interrupt now. Checking it in timer IRQ.
        //OALTimerPerformanceCounterHighUpdate();
        XllpINTCEnableSource(irq,XLLP_FALSE);
		sysIntr = SYSINTR_NOP;
    }

    // Profiling timer interrupt?
    else if (irq == IRQ_OSMR2)
    {
        // Mask the interrupt
        (void) XllpINTCEnableSource(irq,XLLP_FALSE);

        // The rest is up to the profiling interrupt handler (if profiling
        // is enabled).
        //
        if (g_pProfilerISR) {
            sysIntr = g_pProfilerISR(ra);
        }
    }

    else if (irq == IRQ_OSMR3)
    {
            XllpINTCEnableSource(irq,XLLP_FALSE);
            sysIntr = SYSINTR_NOP;            
// Disable temporarily due to OST errata.
// IPM profiler is using OS time service now.
#if 0
        XLLP_UINT32_T compare;
        P_XLLP_OST_T pOSTRegs = (P_XLLP_OST_T)OALPAtoVA(MONAHANS_BASE_REG_PA_OST, FALSE);
        

        

            // IPM idle profiler Window Timer elapsed
            //
            XllpINTCEnableSource(irq,XLLP_FALSE);

            if(TRUE == IPM_WindowDone(&compare))
            {
                sysIntr = iprof_sysintr;         
                //OALMSG(1, (L"OAL:OEMInterruptHandler: SYSINTR_IPMIPROF\r\n"));
            }
            else
                sysIntr = SYSINTR_NOP;

            // The handler will convert the match to ticks ('compare').
            // The xllp will set up the timer and enable the int.
            // Then we will unmask at the INTC.
            //
            XllpOstConfigureMatchReg(pOSTRegs, MatchReg3, compare);
            XllpINTCEnableSource(irq,XLLP_TRUE);
#endif
        
    }

    // for LCD EOF: prototying
    //
    else if(irq == IRQ_LCD)
    {
        volatile XLLP_LCD_REGISTERS_T *pLCDC = (volatile XLLP_LCD_REGISTERS_T *)OALPAtoVA(MONAHANS_BASE_REG_PA_LCD, FALSE);

        XllpINTCEnableSource(irq,XLLP_FALSE);       // mask it

        // See if we need to do anything
        //
        if((pLCDC->lcsr0 & XLLP_LCSR0_EOF0)
		)
        {
            if(gIPM_LCDEOF_FCS)
            {
                // If new HSIO is faster than current, set PCD then HSIO.
                // else set HSIO then PCD
                //
                if(gIPM_Current_OP.hss < gIPM_Next_OP.hss)
                {
					XllpLCDUpdateClock(&xllp_lcd, gIPM_Next_OP.hss);

                    IPM_DoFCS(&gIPM_Next_OP, TRUE, TRUE);
                }
                else if(gIPM_Current_OP.hss > gIPM_Next_OP.hss)
                {
                    // Going Slower.  Set HSS, then PCD.
                    //
                    IPM_DoFCS(&gIPM_Next_OP, TRUE, TRUE);

					XllpLCDUpdateClock(&xllp_lcd, gIPM_Next_OP.hss);
                }
                else
                {
                    // The same HSS. 
                    //
                }

                // Once done with the PCD and HSS, set up a return value for IPM
                //
                sysIntr = SYSINTR_NOP;  //SYSINTR_IPMLCDEOF; // SYSINTRs should not be hard coded.

                // Clear the gvar for next time
                //
                gIPM_LCDEOF_FCS=0;
            }
            else
            {
                // Not changing frequency this time.  NOP
                //
                sysIntr = SYSINTR_NOP;
            }
            
            // Finally, dismiss the interrupt
            //
            pLCDC->lcsr0 = XLLP_LCSR0_EOF0;         // 1 to clear the int
        }
        else
        {
            // unexpected LCDC interrupt.
            OALMSG(1, (L"Unknown IRQ_LCD!!\r\n"));
        }
        XllpINTCEnableSource(irq,XLLP_TRUE);

      
    }
#ifdef ENABLE_RCOMP
    else if (irq == XLLP_INTC_S_DMEM)
    {
        // check if the RCOMP interrupt by read DMCISR[RCI] bit.
        // if so,
        // 1, clear the DMCISR[RCI]
        // 2, read the MDCNFG for DMCISR, use the PCODE and NCODE of it to calculate.
        // 3, write the PAD_XX with the new value.
        XLLP_UINT32_T regIsr;
        P_XLLP_DMEM_REGISTER_T pReg = (P_XLLP_DMEM_REGISTER_T) OALPAtoVA(MONAHANS_BASE_REG_PA_DMEMC, FALSE);
	    XllpINTCEnableSource(irq,XLLP_FALSE);
        regIsr = pReg->dmcisr;
	    if (pReg->dmcisr & XLLP_DMCISR_RCI )
        {
            OALMSG(OAL_INTR, (L"OALIntrInit: irq number %x\r\n", irq));
            pReg->dmcisr &= XLLP_DMCISR_RCI;    //all the bits are write-clear bit or read-only bit.
            OALMSG(OAL_INTR, (L"OALIntrInit: to update Rcomp()\r\n"));
            XllpMemcRcompUpdate( pReg );
        }
	    XllpINTCEnableSource(irq,XLLP_TRUE);
        sysIntr = SYSINTR_NOP;
    }
#endif
    // Board-level interrupts
    else
    {
        UINT32 origIrq = irq;  // save the original so we can tell if it's BSP specific irq
        
		//OALMSG(1, (L"OAL:OEMInterruptHandler: Irq %d\r\n", irq));

        if ((irq == IRQ_GPIO0)||(irq == IRQ_GPIO1))
        {
            // Mask the interrupt
	        (void) XllpINTCEnableSource(irq,XLLP_FALSE);
#ifdef OAL_BSP_CALLBACKS			
            // Give BSP chance to translate IRQ -- if there is subordinate
            // interrupt controller in BSP it give chance to decode its status
            // and change IRQ
            irq = BSPIntrActiveIrq(irq);
#endif            
        } else if(irq == IRQ_GPIOXX_2) {

	        UINT32 gedr, ggroup, i;

			//OALMSG(1, (L"OAL:OEMInterruptHandler: GPIO Irq %d\r\n", irq));

        	if ((g_pGPIO->gedr0)&0xfffffffc) { // don't care GPIO0 and GPIO1
        		gedr = g_pGPIO->gedr0;
        		ggroup = 0;
        	} else if (g_pGPIO->gedr1) {	
        		gedr = g_pGPIO->gedr1;
        		ggroup = 1;
        	} else if (g_pGPIO->gedr2) {
        		gedr = g_pGPIO->gedr2;    
        		ggroup = 2;
        	} else if (g_pGPIO->gedr3) {
        		gedr = g_pGPIO->gedr3;
        		ggroup = 3;        		
        	} else {
        	    //TO-DO: actually, should ASSERT here.
        	    //TEMPORARY FIX: ignore this interrupt to avoid dead loop here
        	    return(SYSINTR_NOP);
             }
        	// Find out which bit causes the IRQ.
        	i = 0;
        	while(!(gedr&0x1)) {
        		gedr = gedr>>1;
        		i++;
        	}
       	    i = i + ggroup*32;
       	    //OALMSG(1, (L"OAL:OEMInterruptHandler: i = %d\r\n", i));
       	    // Get current level on that GPIO
			//XllpGpioGetLevel (g_pGPIO, i, &(g_GPIOPrevLevel[i]));       	    
       	    
       	    // Clear edge detect status first.
       	    
       	    // Don't disable edge detect here. 
       	    // Otherwise, we may lose GPIO edge interrupt. 
       	    // In future, GPIO level interrupt is preferred.
       	    //if (GPIO_RISE&g_GPIOEdgeDetect[i])
       	    //	XllpGpioSetRisingEdgeDetectEnable(g_pGPIO, i, XLLP_OFF);
       	    //if (GPIO_FALL&g_GPIOEdgeDetect[i])
       	    //	XllpGpioSetFallingEdgeDetectEnable(g_pGPIO, i, XLLP_OFF);
        	
        	XllpGpioClearEdgeDetectStatus (g_pGPIO, i);
        	
        	// Compose the IRQ number.		
			irq = IRQ_GPIO_SHARE_BASE - 2 + i;
#ifdef OAL_BSP_CALLBACKS			
            // Give BSP chance to translate IRQ -- if there is subordinate
            // interrupt controller in BSP it give chance to decode its status
            // and change IRQ
            irq = BSPIntrActiveIrq(irq);
#endif
		} else
        {
            // Mask the interrupt
        (void) XllpINTCEnableSource(irq,XLLP_FALSE);
        }

        // First find if IRQ is claimed by chain
        sysIntr = (UINT16)NKCallIntChain((UCHAR)irq);
        //fix the Intallable ISR error according to the MS documents.
        //If the installable ISR returns SYSINTR_NOP, 
        //the BSP interrupt handler code will re-enable the interrupt and 
        //return SYSINTR_NOP. 
        if (sysIntr == SYSINTR_NOP)
        {
            //SETREG32(&g_pICReg->icmr, (1 << irq));  
            (void) XllpINTCEnableSource(irq,XLLP_TRUE);
            return SYSINTR_NOP;
        }
        
        if (sysIntr == (UINT16)SYSINTR_CHAIN || !NKIsSysIntrValid(sysIntr))
        {
            // IRQ wasn't claimed, use static mapping
            sysIntr = OALIntrTranslateIrq(irq);
        }

        // unmask interrupts in case it's NOP or invalid
        if (SYSINTR_NOP == sysIntr) {
            if (origIrq != irq) {
#ifdef OAL_BSP_CALLBACKS
                // BSP specific irq
                BSPIntrEnableIrq (irq);
#endif
				if (origIrq == IRQ_GPIOXX_2) {
		       	    if (GPIO_RISE&g_GPIOEdgeDetect[IRQ_TO_GPIO_NUM(irq)])
		       	    	XllpGpioSetRisingEdgeDetectEnable(g_pGPIO, IRQ_TO_GPIO_NUM(irq), XLLP_ON);
		       	    if (GPIO_FALL&g_GPIOEdgeDetect[IRQ_TO_GPIO_NUM(irq)])
		       	    	XllpGpioSetFallingEdgeDetectEnable(g_pGPIO, IRQ_TO_GPIO_NUM(irq), XLLP_ON);					
				}
            } else
            {
                // Unmask the interrupt
                (void) XllpINTCEnableSource(irq,XLLP_TRUE);
            }
        }

    }
	
    return (sysIntr);
}


//------------------------------------------------------------------------------
//
//  Function:  OEMInterruptHandlerFIQ
//
void OEMInterruptHandlerFIQ()
{
}

//------------------------------------------------------------------------------

